package com.iflytek.autoCompareTool.utils;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.csource.fastdfs.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

import java.io.InputStream;
import java.util.Properties;


/**
 * @author llchen12
 * @date 2018/5/30
 */
public class FastdfsPool {

    private static Logger logger = LoggerFactory.getLogger(FastdfsPool.class);


    private GenericObjectPool<StorageClient1> pool;


    public FastdfsPool(GenericObjectPoolConfig poolConfig, String configFileClassPath) {
        try {
            pool = new GenericObjectPool<>(new FastdfsPooledObjectFactory(configFileClassPath), poolConfig);
        } catch (Exception e) {
            logger.error("初始化fastDFS配置异常", e);
            pool = null;
        }
    }

    public FastdfsPool(String configFileClassPath) {
        try {
            pool = new GenericObjectPool<>(new FastdfsPooledObjectFactory(configFileClassPath), getDefaultConfig());
        } catch (Exception e) {
            logger.error("初始化fastDFS配置异常", e);
            pool = null;
        }
    }

    public GenericObjectPoolConfig getDefaultConfig(){
        GenericObjectPoolConfig config = new GenericObjectPoolConfig();
        // 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true
        config.setBlockWhenExhausted(true);
        // 设置的逐出策略类名,
        // 默认DefaultEvictionPolicy(当连接超过最大空闲时间,或连接数超过最大空闲连接数)
        config.setEvictionPolicyClassName("org.apache.commons.pool2.impl.DefaultEvictionPolicy");
        // 是否启用pool的jmx管理功能, 默认true
        config.setJmxEnabled(true);
        config.setJmxNamePrefix("fastdfs");
        // 是否启用后进先出, 默认true
        config.setLifo(true);
        // 最大空闲连接数, 默认10个
        config.setMaxIdle(5);
        // 最大连接数, 默认500个
        config.setMaxTotal(200);
        // 获取连接时的最大等待毫秒数(如果设置为阻塞时BlockWhenExhausted),如果超时就抛异常,
        // 小于零:阻塞不确定的时间,
        // 默认-1
        config.setMaxWaitMillis(5000);
        // 逐出连接的最小空闲时间
        // 默认1800000毫秒(30分钟)这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义
        config.setMinEvictableIdleTimeMillis(10000);
        // 表示idle object evitor两次扫描之间要sleep的毫秒数；
        config.setTimeBetweenEvictionRunsMillis(1000);
        // 最小空闲连接数, 默认0
        config.setMinIdle(1);
        // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        config.setNumTestsPerEvictionRun(3);
        // 对象空闲多久后逐出, 当空闲时间>该值 且 空闲连接>最大空闲数
        // 时直接逐出,不再根据MinEvictableIdleTimeMillis判断 (默认逐出策略)
        config.setSoftMinEvictableIdleTimeMillis(10000);
        // 在获取连接的时候检查有效性, 默认false
        config.setTestOnBorrow(false);
        // 在空闲时检查有效性, 默认false
        config.setTestWhileIdle(false);
        return config;
    }

    public StorageClient1 getStorageClient1() {
        StorageClient1 client1 = null;
        if (pool != null) {
            try {
                client1 = pool.borrowObject();
            } catch (Exception e) {
                logger.warn("create client error", e);
            }
        }
        return client1;
    }

    public void returnStorageClient1(StorageClient1 storageClient1) {
        if (storageClient1 != null && pool != null) {
            pool.returnObject(storageClient1);
        }
    }


    private class FastdfsPooledObjectFactory extends BasePooledObjectFactory<StorageClient1> {

        private TrackerClient trackerClient;
        private TrackerServer trackerServer;
        private StorageServer storageServer;

        public FastdfsPooledObjectFactory(String configFileClassPath) throws Exception {
            init(configFileClassPath);
        }


        private void init(String configFileClassPath) throws Exception {

            ClassPathResource configResource = new ClassPathResource(configFileClassPath);
            try (InputStream is = configResource.getInputStream()) {
                Properties prop = new Properties();
                prop.load(is);
                ClientGlobal.initByProperties(prop);
                trackerClient = new TrackerClient();
                trackerServer = trackerClient.getConnection();
                storageServer = trackerClient.getStoreStorage(trackerServer);
            } catch (Exception e) {
                throw e;
            }


        }

        @Override
        public StorageClient1 create() throws Exception {
            return new StorageClient1(trackerServer, storageServer);
        }

        @Override
        public PooledObject<StorageClient1> wrap(StorageClient1 storageClient1) {
            return new DefaultPooledObject<>(storageClient1);
        }
    }
}
